package com.mazaiting.emotion.util

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
import androidx.fragment.app.FragmentActivity

/***
 *
 *
 *                                                    __----~~~~~~~~~~~------___
 *                                   .  .   ~~//====......          __--~ ~~
 *                   -.            \_|//     |||\\  ~~~~~~::::... /~
 *                ___-==_       _-~o~  \/    |||  \\            _/~~-
 *        __---~~~.==~||\=_    -_--~/_-~|-   |\\   \\        _/~
 *    _-~~     .=~    |  \\-_    '-~7  /-   /  ||    \      /
 *  .~       .~       |   \\ -_    /  /-   /   ||      \   /
 * /  ____  /         |     \\ ~-_/  /|- _/   .||       \ /
 * |~~    ~~|--~~~~--_ \     ~==-/   | \~--===~~        .\
 *          '         ~-|      /|    |-~\~~       __--~~
 *                      |-~~-_/ |    |   ~\_   _-~            /\
 *                           /  \     \__   \/~                \__
 *                       _--~ _/ | .-~~____--~-/                  ~~==.
 *                      ((->/~   '.|||' -_|    ~~-/ ,              . _||
 *                                 -_     ~\      ~~---l__i__i__i--~~_/
 *                                 _-~-__   ~)  \--______________--~~
 *                               //.-~~~-~_--~- |-------~~~~~~~~
 *                                      //.-~~~--\
 *                               神兽保佑
 *                              代码无BUG!
 * @author mazaiting
 * @date 2019-08-07
 * @description 表情面板
 * 源码来自开源项目https://github.com/dss886/Android-EmotionInputDetector
 */
class SwitchKeyboard {
    /**
     * 活动
     */
    private var mActivity: Activity? = null
    /**
     * 软键盘管理类
     */
    private var mInputManager: InputMethodManager? = null
    /**
     * 数据存储工具
     */
    private var mSp: SharedPreferences? = null
    /**
     * 输入框
     */
    private var mEditText: EditText? = null
    /**
     * 切换布局
     */
    private var mSwtichView: View? = null
    /**
     * 需要绑定的内容view
     */
    private var mContentView: View? = null

    companion object {
        /**
         * 名称
         */
        private const val SHARE_PREFERENCE_NAME = "SwitchKeyboard"
        /**
         * 键盘高度
         */
        private const val SHARE_PREFERENCE_SOFT_INPUT_HEIGHT = "soft_input_height"

        /**
         * 绑定 Activity
         * @param activity 活动
         * @return 当前工具类
         */
        fun with(activity: FragmentActivity): SwitchKeyboard =
            SwitchKeyboard()
                .apply {
                    // 绑定页面
                    mActivity = activity
                    // 获取输入法管理者
                    mInputManager =
                        activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    // 数据存储工具
                    mSp = activity.getSharedPreferences(SHARE_PREFERENCE_NAME, Context.MODE_PRIVATE)
                }
    }

    /**
     * 绑定内容布局
     */
    fun bindToContent(view: View): SwitchKeyboard {
        this.mContentView = view
        return this
    }

    /**
     * 设置切换布局
     * @param switchView 切换布局
     */
    fun setEmotionView(switchView: View): SwitchKeyboard {
        this.mSwtichView = switchView
        return this
    }

    /**
     * 绑定输入框
     * @param editText 输入框
     */
    @SuppressLint("ClickableViewAccessibility")
    fun bindToEditText(editText: EditText): SwitchKeyboard {
        this.mEditText = editText
        editText.requestFocus()
        editText.setOnTouchListener { _, event ->
            if (event.action == MotionEvent.ACTION_UP && null != mSwtichView && mSwtichView!!.isShown) {
                // 显示软件盘时，锁定内容高度，防止跳闪
                lockContentHeight()
                // 隐藏表情布局，显示软件盘
                hideEmotionLayout(true)
                //软件盘显示后，释放内容高度
                editText.postDelayed({ unlockContentHeightDelayed() }, 200L)
            }
            false
        }
        return this
    }

    /**
     * 绑定切换视图按钮
     * @param view 按钮
     */
    fun bindToSwitch(view: View): SwitchKeyboard {
        view.setOnClickListener {
            // 判断是否显示
            if (null != mSwtichView && mSwtichView!!.isShown) {
                // 显示
                // 显示软件盘时，锁定内容高度，防止跳闪。
                lockContentHeight()
                // 隐藏表情布局，显示软件盘
                hideEmotionLayout(true)
                // 软件盘显示后，释放内容高度
                unlockContentHeightDelayed()
            } else {
                // 未显示
                if (isSoftInputShown()) {//同上
                    lockContentHeight()
                    showEmotionLayout()
                    unlockContentHeightDelayed()
                } else {
                    showEmotionLayout()//两者都没显示，直接显示表情布局
                }
            }
        }
        return this
    }

    /**
     * 设置软件盘的模式：SOFT_INPUT_ADJUST_RESIZE
     * 这个属性表示Activity的主窗口总是会被调整大小，从而保证软键盘显示空间。从而方便我们计算软件盘的高度
     */
    fun build(): SwitchKeyboard {
        // 设置键盘模式
        mActivity?.window?.setSoftInputMode(
            WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
                    or WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
        )
        //隐藏软件盘
        hideSoftInput()
        return this
    }

    /**
     * 拦截返回键
     * @return true: 拦截; false: 不拦截
     */
    fun interceptBackPress(): Boolean {
        if (null != mSwtichView && mSwtichView!!.isShown) {
            hideEmotionLayout(false)
            return true
        }
        return false
    }

    /**
     * 锁定内容高度
     */
    private fun lockContentHeight() {
        if (null != mContentView) {
            val params = mContentView!!.layoutParams as LinearLayout.LayoutParams
            params.height = mContentView!!.height
            params.weight = 0.0f
        }
    }

    /**
     * 隐藏表情布局
     * @param isHide 是否隐藏
     */
    private fun hideEmotionLayout(isHide: Boolean) {
        if (null != mSwtichView && mSwtichView!!.isShown) {
            mSwtichView!!.visibility = View.GONE
            if (isHide) {
                showSoftInput()
            }
        }
    }

    /**
     * 软件盘显示后，释放内容高度
     */
    private fun unlockContentHeightDelayed() {
        mEditText?.postDelayed({
            if (null != mContentView) {
                (mContentView!!.layoutParams as LinearLayout.LayoutParams).weight = 1.0f
            }
        }, 200L
        )
    }

    /**
     * 显示标签布局
     */
    private fun showEmotionLayout() {
        // 获取已存储键盘高度
        var softInputHeight = getSupportSoftInputHeight()
        // 若是等于 0, 则计算高度
        if (softInputHeight == 0) {
            softInputHeight = getKeyBoardHeight()
        }
        // 隐藏键盘
        hideSoftInput()
        // 设置布局高度为键盘高度, 并显示布局
        if (null != mSwtichView) {
            mSwtichView!!.layoutParams.height = softInputHeight
            mSwtichView!!.visibility = View.VISIBLE
        }
    }

    /**
     * 编辑框获取焦点，并显示软件盘
     */
    private fun showSoftInput() {
        // 请求焦点
        mEditText?.requestFocus()
        // 显示键盘
        mEditText?.post { mInputManager?.showSoftInput(mEditText, 0) }
    }

    /**
     * 隐藏软件盘
     */
    private fun hideSoftInput() {
        mInputManager?.hideSoftInputFromWindow(mEditText?.windowToken, 0)
    }

    /**
     * 是否显示软件盘
     * @return true: 显示键盘; false: 已显示键盘
     */
    private fun isSoftInputShown(): Boolean {
        return getSupportSoftInputHeight() != 0
    }

    /**
     * 获取软件盘的高度
     * decorView是window中的最顶层view，可以从window中通过getDecorView获取到decorView。
     * 通过decorView获取到程序显示的区域，包括标题栏，但不包括状态栏。
     * @return
     */
    private fun getSupportSoftInputHeight(): Int {
        return if (null != mActivity) {
            val softInputHeight = InputMethodUtil.getSupportSoftInputHeight(mActivity!!)
            //存一份到本地
            if (softInputHeight > 0 && null != mSp) {
                mSp!!.edit().putInt(SHARE_PREFERENCE_SOFT_INPUT_HEIGHT, softInputHeight).apply()
            }
            softInputHeight
        } else {
            0
        }
    }

    /**
     * 获取软键盘高度，由于第一次直接弹出表情时会出现小问题，787是一个均值，作为临时解决方案
     * @return
     */
    private fun getKeyBoardHeight(): Int {
        return if (null != mSp) {
            mSp!!.getInt(SHARE_PREFERENCE_SOFT_INPUT_HEIGHT, 787)
        } else {
            787
        }
    }


}